import { Byte } from '../../api/io/Byte';
import { ITimer } from '../../api/timer/ITimer';
import { IAsync } from '../../api/event/IAsync';



/**战报信息属性枚举*/
export const enum E_BattleReportInfo {
	/**战报类型*/
	REPORT_TYPE = 0,
	/**玩家id*/
	PLAYER_ID = 1,
	/**战斗开始时间*/
	START_TIME = 2,
	/**关卡id*/
	STAGE_ID = 3,
	/**已杀怪物数量*/
	KILL_COUNT = 4,
	/**怪物id*/
	MONSTER_ID = 5,
	/**boss*/
	IS_BOSS = 6,
	/**随机事件id*/
	RANDOM_EVENT_ID = 7,
	/**对手玩家类型*/
	ENEMY_TYPE = 8,
	/**对手玩家id*/
	ENEMY_ID = 9,
	/**竞技场-左边分*/
	ARENA_LEFT_SCORE = 10,
	/**竞技场-右边分*/
	ARENA_RIGHT_SCORE = 11,
	/**枚举数量*/
	EnumCount = 12
}


/**战报信息*/
export class BattleReportInfo {
	/**事件ID*/
	public static readonly EVENT_ID = 'STRUCT_DATA_BATTLE_REPORT_INFO_EVENT_ID';
	/**整体更新事件ID（部分只需要监听整体变化）*/
	public static readonly TOTAL_EVENT_ID = 'STRUCT_DATA_BATTLE_REPORT_INFO_TOTAL_EVENT_ID';
	/**缓存池*/
	private static POOL: BattleReportInfo[] = [];

	/**创建入口*/
	public static create(json?: string): BattleReportInfo {
		const c = this.POOL.pop() || new BattleReportInfo();
		c._destroyed = false;
		c.resetProperty();
		if (json) {
			c.parse(json);
		}
		return c;
	}


	/**已释放*/
	protected _destroyed = false;
	/**战报类型 (uint8)*/
	protected _reportType: number;
	/**玩家id (uint32)*/
	protected _playerId: number;
	/**战斗开始时间 (long)*/
	protected _startTime: number;
	/**关卡id (uint32)*/
	protected _stageId: number;
	/**已杀怪物数量 (uint32)*/
	protected _killCount: number;
	/**怪物id (uint32)*/
	protected _monsterId: number;
	/**boss*/
	protected _isBoss: boolean;
	/**随机事件id (uint32)*/
	protected _randomEventId: number;
	/**对手玩家类型 (uint8)*/
	protected _enemyType: number;
	/**对手玩家id (uint32)*/
	protected _enemyId: number;
	/**竞技场-左边分 (uint32)*/
	protected _arenaLeftScore: number;
	/**竞技场-右边分 (uint32)*/
	protected _arenaRightScore: number;


	/**构建函数-私有，防止外部创建*/
	private constructor() {
	}


	/**释放*/
	public destroy(): void {
		if (this._destroyed) {
			return;
		}
		this._destroyed = true;
		this.resetProperty(true);
		if (BattleReportInfo.POOL.indexOf(this) === -1) {
			BattleReportInfo.POOL.push(this);
		}
	}

	/**战报类型*/
	public get reportType() {
		return this._reportType;
	}


	/**战报类型*/
	public set reportType(v: number) {
		this._reportType = v;
	}


	/**玩家id*/
	public get playerId() {
		return this._playerId;
	}


	/**玩家id*/
	public set playerId(v: number) {
		this._playerId = v;
	}


	/**战斗开始时间*/
	public get startTime() {
		return this._startTime;
	}


	/**战斗开始时间*/
	public set startTime(v: number) {
		this._startTime = v;
	}


	/**关卡id*/
	public get stageId() {
		return this._stageId;
	}


	/**关卡id*/
	public set stageId(v: number) {
		this._stageId = v;
	}


	/**已杀怪物数量*/
	public get killCount() {
		return this._killCount;
	}


	/**已杀怪物数量*/
	public set killCount(v: number) {
		this._killCount = v;
	}


	/**怪物id*/
	public get monsterId() {
		return this._monsterId;
	}


	/**怪物id*/
	public set monsterId(v: number) {
		this._monsterId = v;
	}


	/**boss*/
	public get isBoss() {
		return this._isBoss;
	}


	/**boss*/
	public set isBoss(v: boolean) {
		this._isBoss = v;
	}


	/**随机事件id*/
	public get randomEventId() {
		return this._randomEventId;
	}


	/**随机事件id*/
	public set randomEventId(v: number) {
		this._randomEventId = v;
	}


	/**对手玩家类型*/
	public get enemyType() {
		return this._enemyType;
	}


	/**对手玩家类型*/
	public set enemyType(v: number) {
		this._enemyType = v;
	}


	/**对手玩家id*/
	public get enemyId() {
		return this._enemyId;
	}


	/**对手玩家id*/
	public set enemyId(v: number) {
		this._enemyId = v;
	}


	/**竞技场-左边分*/
	public get arenaLeftScore() {
		return this._arenaLeftScore;
	}


	/**竞技场-左边分*/
	public set arenaLeftScore(v: number) {
		this._arenaLeftScore = v;
	}


	/**竞技场-右边分*/
	public get arenaRightScore() {
		return this._arenaRightScore;
	}


	/**竞技场-右边分*/
	public set arenaRightScore(v: number) {
		this._arenaRightScore = v;
	}



	/**通过枚举获取值*/
	public getV(k: E_BattleReportInfo): any {
		switch (k) {
			case E_BattleReportInfo.REPORT_TYPE: return this._reportType;
			case E_BattleReportInfo.PLAYER_ID: return this._playerId;
			case E_BattleReportInfo.START_TIME: return this._startTime;
			case E_BattleReportInfo.STAGE_ID: return this._stageId;
			case E_BattleReportInfo.KILL_COUNT: return this._killCount;
			case E_BattleReportInfo.MONSTER_ID: return this._monsterId;
			case E_BattleReportInfo.IS_BOSS: return this._isBoss;
			case E_BattleReportInfo.RANDOM_EVENT_ID: return this._randomEventId;
			case E_BattleReportInfo.ENEMY_TYPE: return this._enemyType;
			case E_BattleReportInfo.ENEMY_ID: return this._enemyId;
			case E_BattleReportInfo.ARENA_LEFT_SCORE: return this._arenaLeftScore;
			case E_BattleReportInfo.ARENA_RIGHT_SCORE: return this._arenaRightScore;
			default: return null;
		}
	}


	/**通过枚举设置值*/
	public setV(k: E_BattleReportInfo, v: any): void {
		switch (k) {
			case E_BattleReportInfo.REPORT_TYPE: this._reportType = v; break;
			case E_BattleReportInfo.PLAYER_ID: this._playerId = v; break;
			case E_BattleReportInfo.START_TIME: this._startTime = v; break;
			case E_BattleReportInfo.STAGE_ID: this._stageId = v; break;
			case E_BattleReportInfo.KILL_COUNT: this._killCount = v; break;
			case E_BattleReportInfo.MONSTER_ID: this._monsterId = v; break;
			case E_BattleReportInfo.IS_BOSS: this._isBoss = v; break;
			case E_BattleReportInfo.RANDOM_EVENT_ID: this._randomEventId = v; break;
			case E_BattleReportInfo.ENEMY_TYPE: this._enemyType = v; break;
			case E_BattleReportInfo.ENEMY_ID: this._enemyId = v; break;
			case E_BattleReportInfo.ARENA_LEFT_SCORE: this._arenaLeftScore = v; break;
			case E_BattleReportInfo.ARENA_RIGHT_SCORE: this._arenaRightScore = v; break;
			default: break;
		}
	}


	/**初始化*/
	public resetProperty(fromDestroy = false): void {
		//战报类型
		this._reportType = 0;
		//玩家id
		this._playerId = 0;
		//战斗开始时间
		this._startTime = 0;
		//关卡id
		this._stageId = 0;
		//已杀怪物数量
		this._killCount = 0;
		//怪物id
		this._monsterId = 0;
		//boss
		this._isBoss = false;
		//随机事件id
		this._randomEventId = 0;
		//对手玩家类型
		this._enemyType = 0;
		//对手玩家id
		this._enemyId = 0;
		//竞技场-左边分
		this._arenaLeftScore = 0;
		//竞技场-右边分
		this._arenaRightScore = 0;
	}


	/**序列化*/
	public stringify(toString: boolean): string | any {
		const json: any = {};
		if (this._reportType) {
			json.reportType = this._reportType;
		}
		if (this._playerId) {
			json.playerId = this._playerId;
		}
		if (this._startTime) {
			json.startTime = this._startTime;
		}
		if (this._stageId) {
			json.stageId = this._stageId;
		}
		if (this._killCount) {
			json.killCount = this._killCount;
		}
		if (this._monsterId) {
			json.monsterId = this._monsterId;
		}
		if (this._isBoss) {
			json.isBoss = this._isBoss;
		}
		if (this._randomEventId) {
			json.randomEventId = this._randomEventId;
		}
		if (this._enemyType) {
			json.enemyType = this._enemyType;
		}
		if (this._enemyId) {
			json.enemyId = this._enemyId;
		}
		if (this._arenaLeftScore) {
			json.arenaLeftScore = this._arenaLeftScore;
		}
		if (this._arenaRightScore) {
			json.arenaRightScore = this._arenaRightScore;
		}

		return toString ? JSON.stringify(json) : json;
	}


	/**反序列化*/
	public parse(jsonv: string | any): this {
		this.resetProperty();
		if (!jsonv) {
			return this;
		}
		const json = typeof (jsonv) === 'string' ? JSON.parse(jsonv) : jsonv;
		if (json.reportType) {
			this._reportType = json.reportType;
		}
		if (json.playerId) {
			this._playerId = json.playerId;
		}
		if (json.startTime) {
			this._startTime = json.startTime;
		}
		if (json.stageId) {
			this._stageId = json.stageId;
		}
		if (json.killCount) {
			this._killCount = json.killCount;
		}
		if (json.monsterId) {
			this._monsterId = json.monsterId;
		}
		if (json.isBoss) {
			this._isBoss = json.isBoss;
		}
		if (json.randomEventId) {
			this._randomEventId = json.randomEventId;
		}
		if (json.enemyType) {
			this._enemyType = json.enemyType;
		}
		if (json.enemyId) {
			this._enemyId = json.enemyId;
		}
		if (json.arenaLeftScore) {
			this._arenaLeftScore = json.arenaLeftScore;
		}
		if (json.arenaRightScore) {
			this._arenaRightScore = json.arenaRightScore;
		}
		return this;
	}


	/**序列化-二进制*/
	public toBytes(byte: Byte): void {
		if (!byte) {
			return;
		}
		byte.writeUint8(this._reportType);
		byte.writeUint32(this._playerId);
		byte.writeLongNumber(this._startTime);
		byte.writeUint32(this._stageId);
		byte.writeUint32(this._killCount);
		byte.writeUint32(this._monsterId);
		byte.writeBool(this._isBoss);
		byte.writeUint32(this._randomEventId);
		byte.writeUint8(this._enemyType);
		byte.writeUint32(this._enemyId);
		byte.writeUint32(this._arenaLeftScore);
		byte.writeUint32(this._arenaRightScore);
	}


	/**反序列化-二进制*/
	public fromBytes(byte: Byte): this {
		this.resetProperty();
		if (!byte) {
			return;
		}
		this._reportType = byte.readUint8();
		this._playerId = byte.readUint32();
		this._startTime = byte.readLongNumber();
		this._stageId = byte.readUint32();
		this._killCount = byte.readUint32();
		this._monsterId = byte.readUint32();
		this._isBoss = byte.readBool();
		this._randomEventId = byte.readUint32();
		this._enemyType = byte.readUint8();
		this._enemyId = byte.readUint32();
		this._arenaLeftScore = byte.readUint32();
		this._arenaRightScore = byte.readUint32();
		return this;
	}


	/**克隆*/
	public clone(): BattleReportInfo {
		const byte = Byte.createFromPool();
		this.toBytes(byte);
		byte.pos = 0;
		const clonev = BattleReportInfo.create().fromBytes(byte);
		Byte.recoverToPool(byte);
		return clonev;
	}


	/**处理更新*/
	public processUpdate(jsonv: string): void {
		if (!jsonv) {
			return;
		}

		const eventID = BattleReportInfo.EVENT_ID;
		const us = JSON.parse(jsonv);

		for (let i = 0, len = us.length; i < len;) {
			const idx = us[i];
			//战报类型
			if (idx === E_BattleReportInfo.REPORT_TYPE) {
				const oldv = this._reportType;
				this._reportType = us[i + 1];
				IAsync.dispatch(eventID, idx, this._reportType, oldv);
				i += 2;
				continue;
			}
			//玩家id
			if (idx === E_BattleReportInfo.PLAYER_ID) {
				const oldv = this._playerId;
				this._playerId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._playerId, oldv);
				i += 2;
				continue;
			}
			//战斗开始时间
			if (idx === E_BattleReportInfo.START_TIME) {
				const oldv = this._startTime;
				this._startTime = us[i + 1];
				IAsync.dispatch(eventID, idx, this._startTime, oldv);
				i += 2;
				continue;
			}
			//关卡id
			if (idx === E_BattleReportInfo.STAGE_ID) {
				const oldv = this._stageId;
				this._stageId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._stageId, oldv);
				i += 2;
				continue;
			}
			//已杀怪物数量
			if (idx === E_BattleReportInfo.KILL_COUNT) {
				const oldv = this._killCount;
				this._killCount = us[i + 1];
				IAsync.dispatch(eventID, idx, this._killCount, oldv);
				i += 2;
				continue;
			}
			//怪物id
			if (idx === E_BattleReportInfo.MONSTER_ID) {
				const oldv = this._monsterId;
				this._monsterId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._monsterId, oldv);
				i += 2;
				continue;
			}
			//boss
			if (idx === E_BattleReportInfo.IS_BOSS) {
				const oldv = this._isBoss;
				this._isBoss = us[i + 1];
				IAsync.dispatch(eventID, idx, this._isBoss, oldv);
				i += 2;
				continue;
			}
			//随机事件id
			if (idx === E_BattleReportInfo.RANDOM_EVENT_ID) {
				const oldv = this._randomEventId;
				this._randomEventId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._randomEventId, oldv);
				i += 2;
				continue;
			}
			//对手玩家类型
			if (idx === E_BattleReportInfo.ENEMY_TYPE) {
				const oldv = this._enemyType;
				this._enemyType = us[i + 1];
				IAsync.dispatch(eventID, idx, this._enemyType, oldv);
				i += 2;
				continue;
			}
			//对手玩家id
			if (idx === E_BattleReportInfo.ENEMY_ID) {
				const oldv = this._enemyId;
				this._enemyId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._enemyId, oldv);
				i += 2;
				continue;
			}
			//竞技场-左边分
			if (idx === E_BattleReportInfo.ARENA_LEFT_SCORE) {
				const oldv = this._arenaLeftScore;
				this._arenaLeftScore = us[i + 1];
				IAsync.dispatch(eventID, idx, this._arenaLeftScore, oldv);
				i += 2;
				continue;
			}
			//竞技场-右边分
			if (idx === E_BattleReportInfo.ARENA_RIGHT_SCORE) {
				const oldv = this._arenaRightScore;
				this._arenaRightScore = us[i + 1];
				IAsync.dispatch(eventID, idx, this._arenaRightScore, oldv);
				i += 2;
				continue;
			}

			console.error('[Struct Data] can not find enum in BattleReportInfo with idx = ' + idx + ', version maybe wrong.')
		}

		//全更事件
		ITimer.callLater(this, this.dispatchTotalUpdate);
	}


	/**比对不一致结果*/
	public getCompareInfo(other: BattleReportInfo): string {
		if (!other) {
			return null;
		}

		const updates: any[] = [];

		if (this._reportType !== other._reportType) {
			updates.push(E_BattleReportInfo.REPORT_TYPE, this._reportType);
		}
		if (this._playerId !== other._playerId) {
			updates.push(E_BattleReportInfo.PLAYER_ID, this._playerId);
		}
		if (this._startTime !== other._startTime) {
			updates.push(E_BattleReportInfo.START_TIME, this._startTime);
		}
		if (this._stageId !== other._stageId) {
			updates.push(E_BattleReportInfo.STAGE_ID, this._stageId);
		}
		if (this._killCount !== other._killCount) {
			updates.push(E_BattleReportInfo.KILL_COUNT, this._killCount);
		}
		if (this._monsterId !== other._monsterId) {
			updates.push(E_BattleReportInfo.MONSTER_ID, this._monsterId);
		}
		if (this._isBoss !== other._isBoss) {
			updates.push(E_BattleReportInfo.IS_BOSS, this._isBoss);
		}
		if (this._randomEventId !== other._randomEventId) {
			updates.push(E_BattleReportInfo.RANDOM_EVENT_ID, this._randomEventId);
		}
		if (this._enemyType !== other._enemyType) {
			updates.push(E_BattleReportInfo.ENEMY_TYPE, this._enemyType);
		}
		if (this._enemyId !== other._enemyId) {
			updates.push(E_BattleReportInfo.ENEMY_ID, this._enemyId);
		}
		if (this._arenaLeftScore !== other._arenaLeftScore) {
			updates.push(E_BattleReportInfo.ARENA_LEFT_SCORE, this._arenaLeftScore);
		}
		if (this._arenaRightScore !== other._arenaRightScore) {
			updates.push(E_BattleReportInfo.ARENA_RIGHT_SCORE, this._arenaRightScore);
		}

		const jsonv = updates.length === 0 ? null : JSON.stringify(updates);
		return jsonv;
	}


	/**全部更新*/
	protected dispatchTotalUpdate(): void {
		IAsync.dispatch(BattleReportInfo.TOTAL_EVENT_ID, this.getV(0));
	}

}
